package com.hefan.common.orm.dao;

import com.cat.common.entity.Page;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Created by lxw on 2016/9/26.
 */
@Component("commonDao")
public class CommonDaoImpl implements CommonDao {

    protected Logger logger = LoggerFactory.getLogger(this.getClass());

    private static ConcurrentHashMap<String, Set<Field>> typeFields = new ConcurrentHashMap<String, Set<Field>>();

    private static final String TABLE_FORMATOR = "`%s`";

    @Resource
    protected JdbcTemplate jdbcTemplate;

    @Resource
    protected NamedParameterJdbcTemplate namedParameterJdbcTemplate;

    protected void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    protected JdbcTemplate getJdbcTemplate() {
        return jdbcTemplate;
    }

    protected NamedParameterJdbcTemplate getNamedParameterJdbcTemplate() {
        return namedParameterJdbcTemplate;
    }

    protected void setNamedParameterJdbcTemplate(NamedParameterJdbcTemplate namedParameterJdbcTemplate) {
        this.namedParameterJdbcTemplate = namedParameterJdbcTemplate;
    }

    @Override
    public int update(String sql, Object[] params) {
        return getJdbcTemplate().update(sql,params);
    }

    @Override
    public int update(String sql, List<Object> params) {
        return getJdbcTemplate().update(sql,params.toArray());
    }

    @Override
    public <T> T get(long id, String tableName, Class<T> clazz) {
        String sql = " SELECT * " +
                " FROM " + tableName +
                " WHERE id = ?";
        List<T> list = getJdbcTemplate().query(sql, new Object[]{id}, new BeanPropertyRowMapper<T>(clazz));
        if (CollectionUtils.isNotEmpty(list)) {
            return list.get(0);
        }
        return null;
    }

    @Override
    public<T> T get(String sql, List<Object> params, Class<T> clazz) {
        List<T> list = getJdbcTemplate().query(sql, params.toArray(), new BeanPropertyRowMapper<T>(clazz));
        if (CollectionUtils.isNotEmpty(list)) {
            return list.get(0);
        }
        return null;
    }

    @Override
    public<T> List<T> query(String sql, Object[] params, Class<T> clazz) {
        return getJdbcTemplate().query(sql, params, new BeanPropertyRowMapper<T>(clazz));
    }

    @Override
    public<T> Page<T> findPage(Page<T> page, String sql, Object[] params, Class<T> clazz) {
        String countSql = "SELECT count(1) AS c FROM (" + sql + ") t";
        logger.info(countSql);
        int count = getJdbcTemplate().queryForObject(countSql, params, Integer.class);
        page.setTotalItems(count);
        if (count == 0) {
            return page;
        }
        String pageSql = sql;
        if (StringUtils.isNotBlank(page.getOrderBy()) && StringUtils.isNotBlank(page.getOrder())) {
            pageSql += " ORDER BY " + page.getOrderBy() + " " + page.getOrder() + " ";
        }
        pageSql += " LIMIT " + page.getOffset() + "," + page.getPageSize();

        logger.info(pageSql);
        List<T> result = getJdbcTemplate().query(pageSql, new BeanPropertyRowMapper<T>(clazz), params);
        page.setResult(result);
        return page;
    }

    @Override
    public List<Map<String, Object>> queryMap(String sql) {
        return getJdbcTemplate().queryForList(sql);
    }

    @Override
    public List<Map<String, Object>> queryMap(String sql, Object... params) {
        return getJdbcTemplate().queryForList(sql, params);
    }

    @Override
    public Page<Map<String, Object>> findPageMap(Page<Map<String, Object>> page, String sql, Object... params) {
        String countSql = "SELECT count(1) AS c FROM (" + sql + ") t";
        logger.info(countSql);
        int count = getJdbcTemplate().queryForObject(countSql, params, Integer.class);
        page.setTotalItems(count);
        if (count == 0) {
            return page;
        }

        String pageSql = sql;
        if (StringUtils.isNotBlank(page.getOrderBy()) && StringUtils.isNotBlank(page.getOrder())) {
            pageSql += " ORDER BY " + page.getOrderBy() + " " + page.getOrder() + " ";
        }
        pageSql += " LIMIT " + page.getOffset() + "," + page.getPageSize();
        logger.info(pageSql);
        List<Map<String, Object>> result = getJdbcTemplate().queryForList(pageSql, params);
        page.setResult(result);
        return page;
    }

    public int queryCount(String countSql, Object... params) {
       return getJdbcTemplate().queryForObject(countSql, params, Integer.class);
    }
}
